package com.minelx.datamicroscope.core.index;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.minelx.datamicroscope.core.condition.RawCondition;
import com.minelx.datamicroscope.core.query.AliasedKey;
import com.minelx.datamicroscope.core.query.CollectingResource;
import com.minelx.datamicroscope.core.values.CommonField;
import com.minelx.datamicroscope.core.values.CommonTable;
import com.minelx.hellopandas.core.DataFrameDescription;
import com.minelx.hellopandas.core.PandasMethodProvider;
import io.gitee.minelx.filesystem.Directory;
import io.gitee.minelx.filesystem.File;
import com.minelx.sqlstructures.core.ColumnType;
import com.minelx.sqlstructures.core.values.FieldValues;

import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import static com.minelx.datamicroscope.core.query.Resource.literalColumnType;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;

class FileIndex implements Index {

    private final PandasMethodProvider pandasMethodProvider;

    private final Directory storedDirectory;

    private final List<AliasedKey> remainingKeys;

    private final List<RawCondition> conditions;

    private final CollectingResource collectingResource;

    private final File destination;

    FileIndex(PandasMethodProvider pandasMethodProvider,
              Directory storedDirectory,
              List<AliasedKey> remainingKeys,
              List<RawCondition> conditions,
              CollectingResource collectingResource,
              File destination) {
        this.pandasMethodProvider = pandasMethodProvider;
        this.storedDirectory = storedDirectory;
        this.remainingKeys = remainingKeys;
        this.conditions = conditions;
        this.collectingResource = collectingResource;
        this.destination = destination;
    }

    @Override
    public void list() {
        // building select segment
        JSONArray select = new JSONArray(Stream.concat(remainingKeys.stream(),
                        this.collectingResource.getCollectedFields().stream())
                .map(this::toSelectItem)
                .collect(toList()));

        // building from segment
        CommonTable repositoryTable = this.collectingResource.firstCollectedField().commonTable().primaryKey().commonTable();
        List<FieldValues> fieldsInRepositoryTable = repositoryTable.commonDatabase().structure().table(repositoryTable.name()).getFields();

        Map<String, String> dtypes = fieldsInRepositoryTable.stream().collect(toMap(
                FieldValues::getName,
                fieldValues -> literalColumnType(ColumnType.from(fieldValues.getType()))));
        JSONObject from = DataFrameDescription.create(
                storedDirectory.child().path(repositoryTable.path()).uri(), dtypes).dumpToJSON();

        // building where segment
        JSONArray where = new JSONArray(conditions.stream()
                .map(RawCondition::toJSON)
                .collect(toList()));
        // simplify key of sticky condition
        where.toJavaList(JSONObject.class).stream()
                .filter(which -> which.getString("operator").equals("sticky"))
                .forEach(jsonObject -> jsonObject.put("key", CommonField.from(jsonObject.getString("key")).name()));

        pandasMethodProvider.list(select, from, where, this.destination.path().uri());
    }

    private JSONObject toSelectItem(AliasedKey aliasedKey) {
        JSONObject result = new JSONObject();
        result.put("key", aliasedKey.getKey().name());
        result.put("alias", aliasedKey.getAlias());
        return result;
    }
}
